package iosu.java.games.razer.api.protocol;

import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CARFINISHED_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CARFINISHED_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CARUPDATE_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CARUPDATE_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CLOSING_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CREATEGAME_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.CREATEGAME_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.GAMEFINISHED_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.GAMENOTREADY_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.GAMEREADY_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.GAMEREADY_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.HELLO_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.HELLO_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.JOINGAME_REQUEST;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.NOGAMETOJOIN_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.NOOP_RESPONSE;
import static iosu.java.games.razer.api.protocol.RazerProtocolBase.PLAYERADDED_RESPONSE;

import iosu.java.games.razer.api.CarInfo;

import java.security.InvalidParameterException;
import java.util.Arrays;
import java.util.UUID;

/**
 * Esta clase implementa un mensaje entre cliente y servidor
 * Dependiendo del tipo de mensaje, los posibles contenidos son
 * - fecha en milisegundos
 * - id cliente
 * - 
 * @author iosu
 *
 */
public class RazerProtocolMessage {
	private byte messagetype;
	private byte[] messagecontent;
	
	// para un mensaje de tipo hellorequest, tengo
	private long hora;
	private UUID idcliente;
	private String playername;
	// para un mensaje de tipo helloresponse, joingamerequest, tengo
	private int idfromserver;
	// para un mensaje de tipo playeraddedresponse tengo
	private int numCar;
	// para un mensaje de tipo carupdate_request tengo
	private CarInfo defaultcarupdate;
	// para un mensaje de tipo carupdate_response tengo
	private CarInfo car1update;
	private CarInfo car2update;
	private CarInfo car3update;
	private CarInfo car4update;
	// para un mensaje GAMENOTREADY
	private int numberofplayers;
	
	
	private int[] results;
	private String[] players;
	
	public RazerProtocolMessage(byte type){
		switch(type){
			case HELLO_REQUEST:
				this.messagetype = HELLO_REQUEST;
				break;
			case HELLO_RESPONSE:
				this.messagetype = HELLO_RESPONSE;
				break;
			case CREATEGAME_REQUEST:
				this.messagetype = CREATEGAME_REQUEST;
				break;
			case CREATEGAME_RESPONSE:
				this.messagetype = CREATEGAME_RESPONSE;
				break;
			case JOINGAME_REQUEST:
				this.messagetype = JOINGAME_REQUEST;
				break;
			case NOGAMETOJOIN_RESPONSE:
				this.messagetype = NOGAMETOJOIN_RESPONSE;
				break;
			case PLAYERADDED_RESPONSE:
				this.messagetype = PLAYERADDED_RESPONSE;
				break;
			case GAMEREADY_REQUEST:
				this.messagetype = GAMEREADY_REQUEST;
				break;
			case GAMEREADY_RESPONSE:
				this.messagetype = GAMEREADY_RESPONSE;
				break;	
			case NOOP_RESPONSE:
				this.messagetype = NOOP_RESPONSE;
				break;
			case CARUPDATE_REQUEST:
				this.messagetype = CARUPDATE_REQUEST;
				break;
			case CARUPDATE_RESPONSE:
				this.messagetype = CARUPDATE_RESPONSE;
				break;
			case CLOSING_REQUEST:
				this.messagetype = CLOSING_REQUEST;
				break;
			case CARFINISHED_REQUEST:
				this.messagetype = CARFINISHED_REQUEST;
				break;
			case CARFINISHED_RESPONSE:
				this.messagetype = CARFINISHED_RESPONSE;
				break;
			case GAMEFINISHED_REQUEST:
				this.messagetype = GAMEFINISHED_REQUEST;
				break;
			case GAMENOTREADY_RESPONSE:
				this.messagetype = GAMENOTREADY_RESPONSE;
				break;
			default: throw new UnsupportedOperationException("el codigo "+type+" recibido no se" +
					"corresponde con ningun tipo conocido de mensaje");
		}
	}
	
	public void setMessageContent(byte[] c){
		this.messagecontent = c;
	}
	
	public byte[] getMessageContent(){
		return this.messagecontent;
	}
	
	@Override
	public String toString(){
		StringBuilder sb = new StringBuilder(this.messagecontent.length);
		sb.append("RazerProtocolMessage type: ").append(this.getMesageTypeAsString()).append(", content: ").append(Arrays.toString(this.messagecontent));
		//for (byte b:messagecontent) {
		 //   sb.append(b+'0'); //offset the byte value with the value of char '0'
		//}
		return sb.toString();
	}

	//*************** metodos para HELLO_REQUEST
	public long getHora() {
		return hora;
	}

	public void setHora(long hora) {
		if(this.messagetype!=HELLO_REQUEST) 
			throw new InvalidParameterException("intento de setear hora cuando el mensaje no es de tipo HELLO_REQUEST");
		this.hora = hora;
	}

	public UUID getIdcliente() {
		return idcliente;
	}

	public void setIdcliente(UUID idcliente) {
		this.idcliente = idcliente;
	}
	
	//*************** metodos para HELLO_RESPONSE
	

	//****************** metodos generales
	
	public byte getMessagetype() {
		return messagetype;
	}

	public void setMessagetype(byte messagetype) {
		this.messagetype = messagetype;
	}

	public int getIdfromserver() {
		return idfromserver;
	}

	public void setIdfromserver(int idfromserver) {
		this.idfromserver = idfromserver;
	}

	public int getNumCar() {
		return numCar;
	}

	public void setNumCar(int numCar) {
		this.numCar = numCar;
	}
	
	public String getMesageTypeAsString(){
		switch(this.messagetype){
		case CARUPDATE_REQUEST:
			return "CARUPDATE_REQUEST";
		case CARUPDATE_RESPONSE:
			return "CARUPDATE_RESPONSE";
		case CREATEGAME_REQUEST:
			return "CREATEGAME_REQUEST";
		case CREATEGAME_RESPONSE:
			return "CREATEGAME_RESPONSE";
		case GAMEREADY_REQUEST:
			return "GAMEREADY_REQUEST";
		case GAMEREADY_RESPONSE:
			return "GAMEREADY_RESPONSE";
		case HELLO_REQUEST:
			return "HELLO_REQUEST";
		case HELLO_RESPONSE:
			return "HELLO_RESPONSE";
		case JOINGAME_REQUEST:
			return "JOINGAME_REQUEST";
		case NOGAMETOJOIN_RESPONSE:
			return "NOGAMETOJOIN_RESPONSE";
		case PLAYERADDED_RESPONSE:
			return "PLAYERADDED_RESPONSE";
		case NOOP_RESPONSE:
			return "NOOP_RESPONSE";
		case CLOSING_REQUEST:
			return "CLOSING_REQUEST";
		case CARFINISHED_REQUEST:
		    return "CARFINISHED_REQUEST";
		case CARFINISHED_RESPONSE:
		    return "CARFINISHED_RESPONSE";
		case GAMEFINISHED_REQUEST:
		    return "GAMEFINISHED_REQUEST";
		case GAMENOTREADY_RESPONSE:
			return "GAMENOTREADY_RESPONSE";
		default:
			return null;
		}
	}

	public void setCarUpdate(CarInfo carupdate) {
		this.defaultcarupdate = carupdate;
		
	}

	public CarInfo getDefaultcarupdate() {
		return defaultcarupdate;
	}

	public void setDefaultcarupdate(CarInfo defaultcarupdate) {
		this.defaultcarupdate = defaultcarupdate;
	}

	public CarInfo getCar1update() {
		return car1update;
	}

	public void setCar1update(CarInfo car1update) {
		this.car1update = car1update;
	}

	public CarInfo getCar2update() {
		return car2update;
	}

	public void setCar2update(CarInfo car2update) {
		this.car2update = car2update;
	}

	public CarInfo getCar3update() {
		return car3update;
	}

	public void setCar3update(CarInfo car3update) {
		this.car3update = car3update;
	}

	public CarInfo getCar4update() {
		return car4update;
	}

	public void setCar4update(CarInfo car4update) {
		this.car4update = car4update;
	}
	
	
	@Override
	public boolean equals(Object obj) {
	       if (! (obj instanceof RazerProtocolMessage) ) return false;

	       final RazerProtocolMessage other = (RazerProtocolMessage) obj;
	       // y ahora miro el contenido
	       if (messagetype != other.getMessagetype()){
	           return false;
	       }
	       if(messagecontent!=other.getMessageContent()){
	    	   return false;
	       }
	       return true;

	}

	public void setResults(int[] is) {
		this.results = is;
		
	}
	
	public int[] getResults(){
		return this.results;
	}

	public void setPlayername(String pname) {
		this.playername = pname;
		
	}

	public String getPlayername() {
		return playername;
	}

	public void setNumberOfPlayers(int i) {
		this.numberofplayers = i;
		
	}
	
	public int getNumberOfPlayers(){
		return this.numberofplayers;
	}

	public void setPlayers(String[] players) {
		this.players = players;
		
	}
	
	public String[] getPlayers(){
		return this.players;
	}

}
